135. 分发糖果

135. 分发糖果

Similar Question

406. 根据身高重建队列

Solution Tips

方案一: 哈希表 + 暴力模拟

var candy = function (nums) {
    // 先发送第一轮, 每个孩子一个糖果, 那相当于所有人都没有发
    // 大家都是0也是相等的case, 直接开始发高分糖果, 最后加上1就行
    // 瞻前顾后, 就怕是发了之后不平衡了, 要重新调整
    // 可以想象 AVL 树, 应该是有固定的调整模式的
    // 派负数糖果, 最后回正即可

    // 从得分最低的孩子开始派糖果即可
    // 如何一轮遍历得出顺序?
    const orderMap = {};
    for (let i = 0; i < nums.length; i++) {
        if (!orderMap[nums[i]]) {
            orderMap[nums[i]] = [i];
        }
        else {
            orderMap[nums[i]].push(i);
        }
    }
    const res = Array.from({ length: nums.length });
    // 从最小的开始派糖果
    for (const rateIndexList of Object.values(orderMap)) {
        for (let i = 0; i < rateIndexList.length; i++) {
            const index = rateIndexList[i];
            // 注意相等的时候的 case
            let left = 0;
            if (nums[index] > nums[index - 1]) {
                left = (res[index - 1] || 0)
            }
            let right = 0;
            if (nums[index] > nums[index + 1]) {
                right = (res[index + 1] || 0)
            }
            res[index] = Math.max(left, right) + 1;
        }
    }
    return res.reduce((acc, val) => acc + val, 0);
};
console.log(candy([2,4,1,3,5,8,7]))

方案二: 优先队列 + 模拟

方案三: 贪心

先确定右边评分大于左边的情况(也就是从前向后遍历)

此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果

局部最优可以推出全局最优。

如果 ratings[i] > ratings[i - 1] 那么 [i] 的糖 一定要比 [i - 1] 的糖多一个,所以贪心:candyVec[i] = candyVec[i - 1] + 1

再确定左孩子大于右孩子的情况(从后向前遍历)

遍历顺序这里有同学可能会有疑问,为什么不能从前向后遍历呢?

因为 rating[5] 与 rating[4] 的比较 要利用上 rating[5] 与 rating[6] 的比较结果,所以 要从后向前遍历。

如果从前向后遍历,rating[5] 与 rating[4] 的比较 就不能用上 rating[5] 与 rating[6] 的比较结果了 。如图:

所以确定左孩子大于右孩子的情况一定要从后向前遍历!

如果 ratings[i] > ratings[i + 1],此时 candyVec[i](第 i 个小孩的糖果数量)就有两个选择了,一个是 candyVec[i + 1] + 1(从右边这个加 1 得到的糖果数量),一个是 candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。

那么又要贪心了,局部最优:取 candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第 i 个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。

局部最优可以推出全局最优。

所以就取 candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i] 只有取最大的才能既保持对左边 candyVec[i - 1] 的糖果多,也比右边 candyVec[i + 1] 的糖果多

pCc8kvD.png

var candy = function(ratings) {
    const n = ratings.length;
    const left = new Array(n).fill(0);
    for (let i = 0; i < n; i++) {
        if (i > 0 && ratings[i] > ratings[i - 1]) {
            left[i] = left[i - 1] + 1;
        } else {
            left[i] = 1;
        }
    }

    let right = 0, ret = 0;
    for (let i = n - 1; i > -1; i--) {
        if (i < n - 1 && ratings[i] > ratings[i + 1]) {
            right++;
        } else {
            right = 1;
        }
        ret += Math.max(left[i], right);
    }
    return ret;
};

方案四: 贪心 + 常数空间复杂度

Loading Question... - 力扣(LeetCode)